home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 21 / AACD 21.iso / AACD / Utilities / Ghostscript / src / gp_psync.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-01-01  |  5.8 KB  |  232 lines

  1. /* Copyright (C) 1999, 2000 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of AFPL Ghostscript.
  4.   
  5.   AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author or
  6.   distributor accepts any responsibility for the consequences of using it, or
  7.   for whether it serves any particular purpose or works at all, unless he or
  8.   she says so in writing.  Refer to the Aladdin Free Public License (the
  9.   "License") for full details.
  10.   
  11.   Every copy of AFPL Ghostscript must include a copy of the License, normally
  12.   in a plain ASCII text file named PUBLIC.  The License grants you the right
  13.   to copy, modify and redistribute AFPL Ghostscript, but only under certain
  14.   conditions described in the License.  Among other things, the License
  15.   requires that the copyright notice and this notice be preserved on all
  16.   copies.
  17. */
  18.  
  19. /*$Id: gp_psync.c,v 1.2 2000/09/19 19:00:24 lpd Exp $ */
  20. /* POSIX pthreads threads / semaphore / monitor implementation */
  21. #include "std.h"
  22. #include "malloc_.h"
  23. #include <pthread.h>
  24. #include "gserror.h"
  25. #include "gserrors.h"
  26. #include "gpsync.h"
  27.  
  28. /*
  29.  * Thanks to Larry Jones <larry.jones@sdrc.com> for this revision of
  30.  * Aladdin's original code into a form that depends only on POSIX APIs.
  31.  */
  32.  
  33. /*
  34.  * Some old versions of the pthreads library define
  35.  * pthread_attr_setdetachstate as taking a Boolean rather than an enum.
  36.  * Compensate for this here.
  37.  */
  38. #ifndef PTHREAD_CREATE_DETACHED
  39. #  define PTHREAD_CREATE_DETACHED 1
  40. #endif
  41.  
  42. /* ------- Synchronization primitives -------- */
  43.  
  44. /* Semaphore supports wait/signal semantics */
  45.  
  46. typedef struct pt_semaphore_t {
  47.     int count;
  48.     pthread_mutex_t mutex;
  49.     pthread_cond_t cond;
  50. } pt_semaphore_t;
  51.  
  52. uint
  53. gp_semaphore_sizeof(void)
  54. {
  55.     return sizeof(pt_semaphore_t);
  56. }
  57.  
  58. /*
  59.  * This procedure should really check errno and return something
  60.  * more informative....
  61.  */
  62. #define SEM_ERROR_CODE(scode)\
  63.   (scode != 0 ? gs_note_error(gs_error_ioerror) : 0)
  64.  
  65. int
  66. gp_semaphore_open(gp_semaphore * sema)
  67. {
  68.     pt_semaphore_t * const sem = (pt_semaphore_t *)sema;
  69.     int scode;
  70.  
  71.     if (!sema)
  72.     return -1;        /* semaphores are not movable */
  73.     sem->count = 0;
  74.     scode = pthread_mutex_init(&sem->mutex, NULL);
  75.     if (scode == 0)
  76.     scode = pthread_cond_init(&sem->cond, NULL);
  77.     return SEM_ERROR_CODE(scode);
  78. }
  79.  
  80. int
  81. gp_semaphore_close(gp_semaphore * sema)
  82. {
  83.     pt_semaphore_t * const sem = (pt_semaphore_t *)sema;
  84.     int scode, scode2;
  85.  
  86.     scode = pthread_cond_destroy(&sem->cond);
  87.     scode2 = pthread_mutex_destroy(&sem->mutex);
  88.     if (scode == 0)
  89.     scode = scode2;
  90.     return SEM_ERROR_CODE(scode);
  91. }
  92.  
  93. int
  94. gp_semaphore_wait(gp_semaphore * sema)
  95. {
  96.     pt_semaphore_t * const sem = (pt_semaphore_t *)sema;
  97.     int scode, scode2;
  98.  
  99.     scode = pthread_mutex_lock(&sem->mutex);
  100.     if (scode != 0)
  101.     return SEM_ERROR_CODE(scode);
  102.     while (sem->count == 0) {
  103.         scode = pthread_cond_wait(&sem->cond, &sem->mutex);
  104.         if (scode != 0)
  105.         break;
  106.     }
  107.     if (scode == 0)
  108.     --sem->count;
  109.     scode2 = pthread_mutex_unlock(&sem->mutex);
  110.     if (scode == 0)
  111.     scode = scode2;
  112.     return SEM_ERROR_CODE(scode);
  113. }
  114.  
  115. int
  116. gp_semaphore_signal(gp_semaphore * sema)
  117. {
  118.     pt_semaphore_t * const sem = (pt_semaphore_t *)sema;
  119.     int scode, scode2;
  120.  
  121.     scode = pthread_mutex_lock(&sem->mutex);
  122.     if (scode != 0)
  123.     return SEM_ERROR_CODE(scode);
  124.     if (sem->count++ == 0)
  125.     scode = pthread_cond_signal(&sem->cond);
  126.     scode2 = pthread_mutex_unlock(&sem->mutex);
  127.     if (scode == 0)
  128.     scode = scode2;
  129.     return SEM_ERROR_CODE(scode);
  130. }
  131.  
  132.  
  133. /* Monitor supports enter/leave semantics */
  134.  
  135. uint
  136. gp_monitor_sizeof(void)
  137. {
  138.     return sizeof(pthread_mutex_t);
  139. }
  140.  
  141. int
  142. gp_monitor_open(gp_monitor * mona)
  143. {
  144.     pthread_mutex_t * const mon = (pthread_mutex_t *)mona;
  145.     int scode;
  146.  
  147.     if (!mona)
  148.     return -1;        /* monitors are not movable */
  149.     scode = pthread_mutex_init(mon, NULL);
  150.     return SEM_ERROR_CODE(scode);
  151. }
  152.  
  153. int
  154. gp_monitor_close(gp_monitor * mona)
  155. {
  156.     pthread_mutex_t * const mon = (pthread_mutex_t *)mona;
  157.     int scode;
  158.  
  159.     scode = pthread_mutex_destroy(mon);
  160.     return SEM_ERROR_CODE(scode);
  161. }
  162.  
  163. int
  164. gp_monitor_enter(gp_monitor * mona)
  165. {
  166.     pthread_mutex_t * const mon = (pthread_mutex_t *)mona;
  167.     int scode;
  168.  
  169.     scode = pthread_mutex_lock(mon);
  170.     return SEM_ERROR_CODE(scode);
  171. }
  172.  
  173. int
  174. gp_monitor_leave(gp_monitor * mona)
  175. {
  176.     pthread_mutex_t * const mon = (pthread_mutex_t *)mona;
  177.     int scode;
  178.  
  179.     scode = pthread_mutex_unlock(mon);
  180.     return SEM_ERROR_CODE(scode);
  181. }
  182.  
  183.  
  184. /* --------- Thread primitives ---------- */
  185.  
  186. /*
  187.  * In order to deal with the type mismatch between our thread API, where
  188.  * the starting procedure returns void, and the API defined by pthreads,
  189.  * where the procedure returns void *, we need to create a wrapper
  190.  * closure.
  191.  */
  192. typedef struct gp_thread_creation_closure_s {
  193.     gp_thread_creation_callback_t proc;  /* actual start procedure */
  194.     void *proc_data;            /* closure data for proc */
  195. } gp_thread_creation_closure_t;
  196.  
  197. /* Wrapper procedure called to start the new thread. */
  198. private void *
  199. gp_thread_begin_wrapper(void *thread_data /* gp_thread_creation_closure_t * */)
  200. {
  201.     gp_thread_creation_closure_t closure;
  202.  
  203.     closure = *(gp_thread_creation_closure_t *)thread_data;
  204.     free(thread_data);
  205.     DISCARD(closure.proc(closure.proc_data));
  206.     return NULL;        /* return value is ignored */
  207. }
  208.  
  209. int
  210. gp_create_thread(gp_thread_creation_callback_t proc, void *proc_data)
  211. {
  212.     gp_thread_creation_closure_t *closure =
  213.     (gp_thread_creation_closure_t *)malloc(sizeof(*closure));
  214.     pthread_t ignore_thread;
  215.     pthread_attr_t attr;
  216.     int code;
  217.  
  218.     if (!closure)
  219.     return_error(gs_error_VMerror);
  220.     closure->proc = proc;
  221.     closure->proc_data = proc_data;
  222.     pthread_attr_init(&attr);
  223.     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
  224.     code = pthread_create(&ignore_thread, &attr, gp_thread_begin_wrapper,
  225.               closure);
  226.     if (code) {
  227.     free(closure);
  228.     return_error(gs_error_ioerror);
  229.     }
  230.     return 0;
  231. }
  232.